package com.bajiao.service.recharge.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.bajiao.common.constant._Whole;
import com.bajiao.common.util.*;
import com.bajiao.entity.recharge.RechargeMenu;
import com.bajiao.entity.user.User;
import com.bajiao.service.config.ConfigService;
import com.bajiao.service.recharge.RechargeMenuService;
import com.bajiao.service.user.UserService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bajiao.common.constant.CommonConstant;
import com.bajiao.common.exception.DataHandleException;
import com.bajiao.entity.pay.PayNotifyData;
import com.bajiao.entity.pay.wx.WxPayResult;
import com.bajiao.entity.recharge.Recharge;
import com.bajiao.mapper.recharge.RechargeMapper;
import com.bajiao.service.recharge.RechargeService;
import com.bajiao.third.utils.WxPayUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * @Description: 充值
 * @Author: FanJq
 * @Date: 2024-10-19
 * @Version: V1.0
 */
@Service
@Slf4j
public class RechargeServiceImpl extends ServiceImpl<RechargeMapper, Recharge> implements RechargeService {

    @Resource
    private WxPayUtils wxPayUtils;
    @Resource
    private RechargeMenuService menuService;
    @Resource
    private ConfigService configService;
    @Resource
    private RedisUtil redisUtil;
    @Resource
    private UserService userService;

    /**
     * @Description
     * 获取充值菜单
     * @date 2024/12/25 10:36
     * @author FanJq
     * @param
     * @return {@link List< RechargeMenu>}
    */
    @Override
    public List<RechargeMenu> getMenuList() {
        return menuService.getMenuList();
    }

    /**
     * @Description
     * 充值单失效
     * @date 2024/12/25 11:37
     * @author FanJq
     * @param recharge
     * @return
    */
    @Override
    @Async("taskExecutor")
    public void expiredEvent(Recharge recharge) {
        super.lambdaUpdate()
                .set(Recharge::getOrderStatus, _Whole.THREE)
                .eq(Recharge::getOrderStatus, _Whole.ONE)
                .eq(Recharge::getId, recharge.getId())
                .update();
    }

    /**
     * @Description
     * 微信支付
     * @date 2024/12/25 10:56
     * @author FanJq
     * @param request
     * @param user
     * @param menuId
     * @param source
     * @return {@link WxPayResult}
    */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public WxPayResult wxPay(HttpServletRequest request, User user, String menuId, String source) {
        String callback = configService.getCallback("wxRecharge");
        if (StrUtil.isBlank(callback) || !callback.contains("http"))
            throw new DataHandleException("支付失败，请检查支付配置");
        //创建订单
        Recharge recharge = createOrder(user.getId(), menuId, CommonConstant.PAYMENT_TYPE_WX);
        String result = "";
        if (source.equals("applet")) {
            if (StrUtil.isBlank(user.getOpenId()))
                throw new DataHandleException("openId不存在，支付失败");
            //@create by FanJq 2024/12/25 11:16 小程序支付
            result = wxPayUtils.miniAppPay(request, user.getOpenId(), recharge.getPaymentNo(), String.valueOf(recharge.getPayPrice()), "充值美豆", callback, "");
        } else {
            //@create by FanJq 2024/12/25 11:16 app支付
            result = wxPayUtils.payApp(request, recharge.getPaymentNo(), String.valueOf(recharge.getPayPrice()), "充值美豆", callback, "");
        }
        if (StrUtil.isBlank(result))
            throw new DataHandleException("支付失败");
        WxPayResult wxPayResult = WxPayResult.WxPayResultBuilder.aWxPayResult()
                .orderNo(recharge.getOrderNo())
                .orderId(recharge.getId())
                .result(FastJsonHelper.toBean(result, Map.class))
                .payMoney(recharge.getPayPrice())
                .build();
        return wxPayResult;
    }

    /**
     * @Description
     * 根据支付编号获取
     * @date 2024/12/25 11:45
     * @author FanJq
     * @param paymentNo
     * @return {@link Recharge}
    */
    public Recharge getByPaymentNo(String paymentNo) {
        return super.lambdaQuery().eq(Recharge::getPaymentNo, paymentNo).one();
    }

    /**
     * @Description
     * 支付成功逻辑
     * @date 2024/12/25 11:54
     * @author FanJq
     * @param payNotifyData
     * @return
    */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void completePayment(PayNotifyData payNotifyData) {
        log.info("进入充值回调方法 =================>>>>>>>>> 时间："+DateUtil.now());
        //付款编号
        String paymentNo = payNotifyData.getOutTradeNo();
        //支付交易码
        String tradeNo = payNotifyData.getTradeNo();
        //支付时间
        Date payTime = payNotifyData.getPayTime();
        //支付方式
        Integer type = payNotifyData.getType();

        //@create by FanJq 2024/12/25 11:53 实付金额
        BigDecimal payPrice = new BigDecimal(payNotifyData.getTotalMoney()).divide(new BigDecimal("100"), _Whole.TWO, BigDecimal.ROUND_DOWN);

        Recharge recharge = this.getByPaymentNo(paymentNo);
        if (recharge == null) {
            log.error("充值回调异常！ paymentNo：{}，支付方式：{}，时间：{}", paymentNo, type == CommonConstant.PAYMENT_TYPE_WX ? "微信支付" : "支付宝支付", DateUtil.now());
            return;
        }
        if (recharge.getOrderStatus() == CommonConstant.ORDER_STATUS_FINISHED)
            return;

        //@create by FanJq 2024/12/25 11:47 删除失效事件
        redisUtil.del(_Whole.rechargeOrderExpiredKey + recharge.getId());
        recharge.setPayPrice(payPrice);
        recharge.setPayTime(payTime);
        recharge.setOutTradeNo(tradeNo);
        recharge.setOrderStatus(CommonConstant.ORDER_STATUS_FINISHED);
        recharge.setFinishTime(new Date());
        if (super.updateById(recharge)) {
            //@create by FanJq 2024/12/25 11:55 计算本次充值获得金币总额
            BigDecimal totalAmount = recharge.getAmount().add(recharge.getGiveAmount());
            if (totalAmount.signum() > _Whole.ZERO) {
                //@create by FanJq 2024/12/25 12:00 增加金币和生成流水
                String title = "充值" + recharge.getAmount().stripTrailingZeros().toPlainString();
                if (recharge.getGiveAmount().signum() > _Whole.ZERO) {
                    title = title + "赠送" + recharge.getGiveAmount().stripTrailingZeros().toPlainString();
                }
                userService.changeMoney(recharge.getUserId(), totalAmount, _Whole.ONE, recharge.getOrderNo(), title, _Whole.ONE);
            }
        }
    }

    /**
     * @Description
     * 创建订单
     * @date 2024/12/25 10:57
     * @author FanJq
     * @param userId
     * @param menuId
     * @param paymentType
     * @return {@link Recharge}
    */
    private Recharge createOrder(String userId, String menuId, Integer paymentType) {
        RechargeMenu menu = menuService.getById(menuId);
        if (ObjectUtil.isNull(menu))
            throw new DataHandleException("充值选项数据异常");
        Recharge recharge = new Recharge();
        recharge.setOrderNo(UUIDGenerator.getOrderNoByTime(_Whole.rechargeOrderNoPrefix));
        recharge.setUserId(userId);
        recharge.setRechargeMoney(menu.getPrice());
        recharge.setPaymentType(paymentType);
        recharge.setPaymentNo(IDGeneratorUtils.getStringId());
        recharge.setOrderStatus(CommonConstant.ORDER_STATUS_PENDING_PAYMENT);
        recharge.setGiveAmount(menu.getGiveAmount());
        recharge.setAmount(menu.getAmount());
        recharge.setPayPrice(menu.getPrice());
        boolean b = super.save(recharge);
        if (b) {
            //@create by FanJq 2024/12/25 11:24 30分钟未完成充值 订单失效
            redisUtil.set(_Whole.rechargeOrderExpiredKey + recharge.getId(), recharge.getId(), 60 * 30);
            return recharge;
        }
        throw new DataHandleException("创建充值单失败");
    }
}
